#pragma once

#include <QString>
#include "FeatureShape.h"
#include <iostream>
#include <fstream>

enum class BooleanOP : uint8_t;

enum class EOperationType : uint8_t
{
	None,
    Create,
    Delete,
    Hollow,
    Revolve,
    RoundOff,
    Stretch,
    Boolean,
	Transform,
	Sketch,
	FillFace,
	CreateFromObject,
	DetachEdge,
	DetachFace,
	UncoverFace,
	CoverFace,
	MoveFace,
	MoveEdge,
	Section
};

class ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
    ShapeOperation() = default;
	ShapeOperation(QString name) : operationName(name) {}
public:
	QString operationName;
	EOperationType m_operationType = EOperationType::None;

	// 序列化函数
	virtual void serialize(std::ofstream& out) const;
	// 反序列化函数
	virtual void deserialize(std::ifstream& in);

	static std::shared_ptr<FeatureShape> deserializeFeatureShape(std::ifstream& in);
};

// 创建基础形状
class CreateShapeOperation : public ShapeOperation
{
    friend class QShapeVersion;
    friend class HistoryManager;
public:
	CreateShapeOperation() { m_operationType = EOperationType::Create; }
	CreateShapeOperation(QString name, std::shared_ptr<FeatureShape> featureShape) : ShapeOperation(name), m_featureShape(featureShape)
	{
		m_operationType = EOperationType::Create;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

public:
	std::shared_ptr<FeatureShape> m_featureShape;
};

class BooleanOperation : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
	BooleanOperation() { m_operationType = EOperationType::Boolean; }
	BooleanOperation(QString name, int targetShape, int toolShape, BooleanOP booleanStyle)
		: ShapeOperation(name), m_targetShape(targetShape), m_toolShape(toolShape), m_booleanStyle(booleanStyle) 
	{
		m_operationType = EOperationType::Boolean;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

public:
	BooleanOP m_booleanStyle;
	int m_targetShape = -1;
	int m_toolShape = -1;
};

class DeleteShapeOperation : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
    DeleteShapeOperation() { m_operationType = EOperationType::Delete; }
	DeleteShapeOperation(QString name, const std::vector<int>& shapeIndex) : ShapeOperation(name), m_shapeIndex(shapeIndex)
	{
		m_operationType = EOperationType::Delete;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

public:
	std::vector<int> m_shapeIndex;
};

class TransformOperation : public ShapeOperation
{
    friend class QShapeVersion;
    friend class HistoryManager;
public:
    TransformOperation() { m_operationType = EOperationType::Transform; }
    TransformOperation(QString name, std::vector<int> shapeIndex, gp_Trsf transform) 
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_transform(transform)
	{
		m_operationType = EOperationType::Transform;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

public:
	std::vector<int> m_shapeIndex;
	gp_Trsf m_transform;
};

class HollowOperation : public ShapeOperation
{
    friend class QShapeVersion;
    friend class HistoryManager;
public:
    HollowOperation() { m_operationType = EOperationType::Hollow; }
    HollowOperation(QString name, int shapeIndex, float thickness, const std::vector<int>& subFaceIndex) 
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_thickness(thickness), m_subFaceIndex(subFaceIndex)
	{
		m_operationType = EOperationType::Hollow;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

public:
	int m_shapeIndex = -1;
	std::vector<int> m_subFaceIndex;
	float m_thickness = 0.f;
};

class StretchOperation : public ShapeOperation
{
    friend class QShapeVersion;
    friend class HistoryManager;
public:
    StretchOperation() { m_operationType = EOperationType::Stretch; }
    StretchOperation(QString name, int shapeIndex, const std::vector<int>& subShapeIndex, const gp_Vec& stretchVector, bool bIsEdge)
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_subShapeIndex(subShapeIndex), m_stretchVector(stretchVector), m_bIsEdge(bIsEdge)
	{
		m_operationType = EOperationType::Stretch;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

public:
	int m_shapeIndex = -1;
	std::vector<int> m_subShapeIndex;
	gp_Vec m_stretchVector;
	bool m_bIsEdge = false;
};

class RevolveOperation : public ShapeOperation
{
    friend class QShapeVersion;
    friend class HistoryManager;
public:
    RevolveOperation() { m_operationType = EOperationType::Revolve; }
    RevolveOperation(QString name, int shapeIndex, const std::vector<int> subShapeIndex, float angle, const gp_Ax1& rotationAxis, bool bUseEdge)
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_subShapeIndex(subShapeIndex), 
		m_angle(angle), m_rotationAxis(rotationAxis), m_bUseEdge(bUseEdge)
	{
		m_operationType = EOperationType::Revolve;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

public:
	int m_shapeIndex = -1;
	std::vector<int> m_subShapeIndex;
	float m_angle = 0.f;
	gp_Ax1 m_rotationAxis;
	bool m_bUseEdge = false;
};

class RoundOffOperation : public ShapeOperation
{
    friend class QShapeVersion;
    friend class HistoryManager;
public:
    RoundOffOperation() { m_operationType = EOperationType::RoundOff; }
    RoundOffOperation(QString name, int shapeIndex, const std::vector<int>& subShapeIndex, float radius)
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_subShapeIndex(subShapeIndex), m_radius(radius)
	{
		m_operationType = EOperationType::RoundOff;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

public:
	int m_shapeIndex = -1;
	std::vector<int> m_subShapeIndex;
	float m_radius = 0.f;
};

class SketchOperation : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
	SketchOperation() { m_operationType = EOperationType::Sketch; }
	SketchOperation(QString name, const gp_Dir& normal, const gp_Dir& right, const gp_Pnt& center, 
		std::vector<std::shared_ptr<FeatureShape>> featureShapes)
		: ShapeOperation(name), m_normal(normal), m_right(right), m_center(center), m_featureShapes(featureShapes)
	{
		m_operationType = EOperationType::Sketch;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

public:
	gp_Dir m_normal;
    gp_Dir m_right;
    gp_Pnt m_center;
    std::vector<std::shared_ptr<FeatureShape>> m_featureShapes;
};

class FillFaceOperation : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
	FillFaceOperation() { m_operationType = EOperationType::FillFace; }
	FillFaceOperation(QString name, std::vector<std::pair<int, std::vector<int>>> shapeIDs)
		: ShapeOperation(name), m_shapeIndex(shapeIDs)
	{
		m_operationType = EOperationType::FillFace;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

public:
	std::vector<std::pair<int, std::vector<int>>> m_shapeIndex;
};

class CreateShapeFromObjectOperatopn : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
    CreateShapeFromObjectOperatopn() { m_operationType = EOperationType::CreateFromObject; }
    CreateShapeFromObjectOperatopn(QString name, int shapeIndex, int subShapeIndex, bool UseEdge)
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_subShapeIndex(subShapeIndex), bUseEdge(UseEdge)
	{
		m_operationType = EOperationType::CreateFromObject;
	}

    virtual void deserialize(std::ifstream& in) override;
    virtual void serialize(std::ofstream& out) const override;
public:
	int m_shapeIndex = -1;// 现目前只考虑单选
	int m_subShapeIndex = -1;
	bool bUseEdge = false;
};

class DetachEdgeOperation : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
	DetachEdgeOperation() { m_operationType = EOperationType::DetachEdge; }
	DetachEdgeOperation(QString name, int shapeIndex, int subShapeIndex)
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_subShapeIndex(subShapeIndex)
	{
		m_operationType = EOperationType::DetachEdge;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;
public:
	int m_shapeIndex = -1;
	int m_subShapeIndex = -1;
};

class DetachFaceOperation : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
	DetachFaceOperation() { m_operationType = EOperationType::DetachFace; }
	DetachFaceOperation(QString name, int shapeIndex, int subShapeIndex)
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_subShapeIndex(subShapeIndex)
	{
		m_operationType = EOperationType::DetachFace;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;
public:
	int m_shapeIndex = -1;
	int m_subShapeIndex = -1;
};

class UncoverFaceOperation : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
	UncoverFaceOperation() { m_operationType = EOperationType::UncoverFace; }
	UncoverFaceOperation(QString name, int shapeIndex, int subShapeIndex)
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_subShapeIndex(subShapeIndex)
	{
		m_operationType = EOperationType::UncoverFace;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;
public:
	int m_shapeIndex = -1;
	int m_subShapeIndex = -1;
};

class CoverFaceOperation : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
	CoverFaceOperation() { m_operationType = EOperationType::CoverFace; }
	CoverFaceOperation(QString name, int shapeIndex)
		: ShapeOperation(name), m_shapeIndex(shapeIndex)
	{
		m_operationType = EOperationType::CoverFace;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;
public:
	int m_shapeIndex = -1;
};

class MoveFaceOperation : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
	MoveFaceOperation() { m_operationType = EOperationType::MoveFace; }
	MoveFaceOperation(QString name, int shapeIndex, int subShapeIndex, gp_Vec moveVec)
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_subShapeIndex(subShapeIndex), m_moveVec(moveVec)
	{
		m_operationType = EOperationType::MoveFace;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;
public:
	int m_shapeIndex = -1;
	int m_subShapeIndex = -1;
	gp_Vec m_moveVec;
};

class MoveEdgeOperation : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
	MoveEdgeOperation() { m_operationType = EOperationType::MoveEdge; }
	MoveEdgeOperation(QString name, int shapeIndex, int subShapeIndex, float moveDistance)
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_subShapeIndex(subShapeIndex), m_moveDistance(moveDistance)
	{
		m_operationType = EOperationType::MoveEdge;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;
public:
	int m_shapeIndex = -1;
	int m_subShapeIndex = -1;
	float m_moveDistance = 0.f;
};

class SectionOperation : public ShapeOperation
{
	friend class QShapeVersion;
	friend class HistoryManager;
public:
	SectionOperation() { m_operationType = EOperationType::Section; }
	SectionOperation(QString name, int shapeIndex, int planeIndex)
		: ShapeOperation(name), m_shapeIndex(shapeIndex), m_planeIndex(planeIndex)
	{
		m_operationType = EOperationType::Section;
	}

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;
public:
	int m_shapeIndex = -1;
	int m_planeIndex = -1;
};

// ------------------------------------------------Operation End------------------------------------------------//

class ShapeOperationFactory
{
public:
	static ShapeOperation* CreateOperation(EOperationType operationType);
};